using System;
using System.Collections;
using System.Text;
using System.Data;
using System.ComponentModel;
using System.Text.RegularExpressions;

using CodeSmith.Engine;
using SchemaExplorer;
using CodeSmith.CustomProperties;

using System.Xml;


namespace CodeSmith.MiniAccess
{
    public class TemplateBase : CodeSmith.Engine.CodeTemplate 
    {
		private string className = null;
		private ColumnSchemaCollection primaryKeyColumns = null;
		private ColumnSchema identityColumn = null;
		private ColumnSchemaCollection allColumns = null;
		
		protected void Init(SchemaExplorer.TableSchema table, string prefix)
		{
			className = GetClassName(table, prefix);
			
			identityColumn = GetIdentityColumn(table);
			if( table.HasPrimaryKey)
				primaryKeyColumns = table.PrimaryKey.MemberColumns;

			allColumns = table.Columns;
		}
		
		protected string ClassName
		{
			get { return className; }
		}
		
		protected ColumnSchema IdentityColumn
		{
			get { return identityColumn; }
		}
		protected string GetClassName(SchemaExplorer.TableSchema table, string prefix)
		{
            string tname = TrimTableName(table.Name, prefix );
			return GetPascle( Join(tname.Split(' '),"_") + "Entity" );
		}
        
        protected string TrimTableName(string tableName, string prefix)
        {
            string tname = tableName;
            if(  !string.IsNullOrEmpty(prefix) && tname.StartsWith(prefix) )
            {
                tname = tname.Substring( prefix.Length );
            }
            return tname;
        }
			
		protected ColumnSchemaCollection PrimaryKeyColumns
		{
			get { return primaryKeyColumns; }
		}
		
		protected ColumnSchemaCollection AllColumns
		{
			get { return allColumns; }
		}
		
		protected string GetKeyParameters()
		{
			string s = "";
			for(int i=0;i<primaryKeyColumns.Count;i++ ) 
			{
				s += GetCSType(primaryKeyColumns[i]) + " " + GetMemberVariableName(primaryKeyColumns[i]);
				if(i<primaryKeyColumns.Count-1)
					s += ",";
			}
			return s;
		}

		protected string GetKeyValues()
		{
			string s = "";
			for(int i=0;i<primaryKeyColumns.Count;i++ ) 
			{
				s += GetMemberVariableName(primaryKeyColumns[i]);
				if(i<primaryKeyColumns.Count-1)
					s += ",";
			}
			return s;
		}
		
		protected string Join(string[] args,string con)
		{
			StringBuilder br=new StringBuilder();
			for(int i=0;i<args.Length;i++)
			{
				br.Append(args[i]);
				if(i<args.Length-1)
				{
					br.Append(con);
				}
			}
			return br.ToString();
		}
		
		protected bool IsIdentity(ColumnSchema column)
		{
			if ( (bool)column.ExtendedProperties["CS_IsIdentity"].Value == true )
				return true;
			else
				return false;
		}
		
		protected ColumnSchema GetIdentityColumn(TableSchema table)
		{
			for(int i=0;i<table.Columns.Count;i++)
			{
				if(IsIdentity(table.Columns[i])==true)
					return table.Columns[i];
			}
			return null;
		}
		
		protected ColumnSchemaCollection RemoveIdentityColumnsFromCollection(ColumnSchemaCollection from,ColumnSchema idenColumn)
		{
			ColumnSchemaCollection coll=new ColumnSchemaCollection();
			if(idenColumn!=null&&from.Contains(idenColumn))
			{
				for(int i=0;i<from.Count;i++)
				{
					if(idenColumn!=from[i])	coll.Add(from[i]);
				}
			}
			else{
				coll=from;
			}
			return coll;
		}
		
		protected string GetCamel(string str)
		{
			if(str==null||str=="")
				return "";
			else 
				return str.Substring(0,1).ToLower()+str.Substring(1);
		}
		
		protected string GetPascle(string str)
		{
			if(str==null||str=="")
				return "";
			else
				return str.Substring(0,1).ToUpper()+str.Substring(1);
		}
		
		protected string GetMemberVariableName(ColumnSchema column)
		{
			//return GetCamel(column.Name);
            string name = GetCamel(column.Name);
            if( name=="isNew" || name=="isDelete" )
            {
                name = name + "_Field";
            }
            return name;
		}
		
		protected string GetMemberVariableName(ColumnSchema column,string prefix)
		{
			return prefix + GetPascle(column.Name);
		}
		
		protected string GetPropertyName(ColumnSchema column)
		{
			//return GetPascle(column.Name);
            string name = GetPascle(column.Name);
            if( name=="IsNew" || name=="IsDelete" )
            {
                name = name + "_Field";
            }
            return name;
		}
		
		protected string GetPropertyName(ColumnSchema column,string prefix)
		{
			return prefix + GetPascle(column.Name);
		}
		
		protected int GetColumnSize(ColumnSchema column)
		{
			return column.Size;
		}
		
		protected string GetCSType(ColumnSchema column)
		{
			if (column.Name.EndsWith("TypeCode")) return column.Name;
			
			string type = "";
			switch (column.DataType)
			{
				case DbType.AnsiString: type = "string"; break;
				case DbType.AnsiStringFixedLength:  type =  "string"; break;
				case DbType.Binary:  type =  "byte[]"; break;
				case DbType.Boolean:  type =  "bool"; break;
				case DbType.Byte:  type =  "byte"; break;
				case DbType.Currency:  type =  "decimal"; break;
				case DbType.Date:  type =  "DateTime"; break;
				case DbType.DateTime:  type =  "DateTime"; break;
				case DbType.Decimal:  type =  "decimal"; break;
				case DbType.Double:  type =  "double"; break;
				case DbType.Guid:  type =  "Guid"; break;
				case DbType.Int16:  type =  "short"; break;
				case DbType.Int32:  type =  "int"; break;
				case DbType.Int64:  type =  "long"; break;
				case DbType.Object:  type =  "object"; break;
				case DbType.SByte:  type =  "sbyte"; break;
				case DbType.Single:  type =  "float"; break;
				case DbType.String:  type =  "string"; break;
				case DbType.StringFixedLength:  type =  "string"; break;
				case DbType.Time:  type =  "TimeSpan"; break;
				case DbType.UInt16:  type =  "ushort"; break;
				case DbType.UInt32:  type =  "uint"; break;
				case DbType.UInt64:  type =  "ulong"; break;
				case DbType.VarNumeric:  type =  "decimal"; break;
				default:
				{
					 type =  "__UNKNOWN__" + column.NativeType; break;
				}
				
			}
			
			// 上述类型中除了 string 和 object 外都是值类型，如果字段允许为空，则使用可空类型。
			if( ( type!="string" && type!="object"  && type!="byte[]") && column.AllowDBNull )
			{
				type = type+"?";
			}
			return type;
		}
		protected string GetDefaultValue(ColumnSchema column)
		{
			switch (column.DataType)
			{
				case DbType.Guid:
				{
					return " = Guid.Empty";
				}
				case DbType.AnsiString:
				case DbType.AnsiStringFixedLength:
				case DbType.String:
				case DbType.StringFixedLength:
				{
					return " = String.Empty";
				}
				case DbType.Decimal:
				case DbType.VarNumeric:
				case DbType.Currency:
					return " = 0.0M";
				case DbType.Double:
				case DbType.Single:
					return " = 0.0";
					
				case DbType.Int16:
				case DbType.Int32:
				case DbType.Int64:
				case DbType.UInt16:
				case DbType.UInt32:
				case DbType.UInt64:
				case DbType.SByte:
					return " = 0";
				
				case DbType.DateTime:
					return " = DateTime.MaxValue";
				default:
				{
					return "";
				}
			}
		}
		
		protected string GetSqlDbTypeFromColumn(ColumnSchema column)
		{
			switch (column.NativeType)
			{
				case "bigint": return "BigInt";
				case "binary": return "Binary";
				case "bit": return "Bit";
				case "char": return "Char";
				case "datetime": return "DateTime";
				case "decimal": return "Decimal";
				case "float": return "Float";
				case "image": return "Image";
				case "int": return "Int";
				case "money": return "Money";
				case "nchar": return "NChar";
				case "ntext": return "NText";
				case "numeric": return "Decimal";
				case "nvarchar": return "NVarChar";
				case "real": return "Real";
				case "smalldatetime": return "SmallDateTime";
				case "smallint": return "SmallInt";
				case "smallmoney": return "SmallMoney";
				case "sql_variant": return "Variant";
				case "sysname": return "NChar";
				case "text": return "Text";
				case "timestamp": return "Timestamp";
				case "tinyint": return "TinyInt";
				case "uniqueidentifier": return "UniqueIdentifier";
				case "varbinary": return "VarBinary";
				case "varchar": return "VarChar";
				default: return "__UNKNOWN__" + column.NativeType;
			}
		}
		

		//取得父表中与子表外键列对应的列
		protected ColumnSchema GetParentPrimaryKeyColumn( TableSchema table, ColumnSchema column)
		{
			foreach (TableKeySchema foreignKeyTable in table.ForeignKeys) 
			{
				for (int i = 0; i < foreignKeyTable.ForeignKeyMemberColumns.Count; i++)
				{
					if (foreignKeyTable.ForeignKeyMemberColumns[i].Name == column.Name)
					{
						return foreignKeyTable.PrimaryKeyMemberColumns[i];
					}
				}
			}
			return null;
		}
		
		// 取得外键对应表名
		protected string GetTableNameOfForeignKey( TableSchema table, ColumnSchema column) 
		{
			foreach (TableKeySchema foreignKeyTable in table.ForeignKeys) 
			{
				foreach (ColumnSchema foreignColumn in foreignKeyTable.ForeignKeyMemberColumns) 
				{
					if (foreignColumn.Name == column.Name) {
						return GetPascle(Join(foreignKeyTable.PrimaryKeyTable.Name.Split(' '),"_"));
					}
				}
			} 
			return string.Empty;
		}
		
		
		protected string GetIndexParameters( IndexSchema index)
		{
			string s = "";
			for(int i=0;i<index.MemberColumns.Count;i++ ) 
			{
				s += GetCSType(index.MemberColumns[i]) + " " + GetMemberVariableName(index.MemberColumns[i]);
				if(i<index.MemberColumns.Count-1)
					s += ",";
			}
			return s;
		}

		protected string GetIndexCondition(IndexSchema index)
		{
			string s = "\"WHERE \" + ";
			for(int i=0;i<index.MemberColumns.Count;i++ ) 
			{
				s += "\n\t\t\t\t" + GetWhereExpress(index.MemberColumns[i]);
				if(i<index.MemberColumns.Count-1)
					s += " + \" AND \" + ";
			}
			return s;
		}
		
		protected string GetWhereExpress(ColumnSchema column)
		{
			string type = GetCSType(column);
			switch( type )
			{
				case "sbyte":
				case "byte":
				case "short":
				case "ushort":
				case "int":
				case "uint":
				case "long":
				case "ulong":
				case "decimal":
				case "float":
				case "double":
				case "TimeSpan":
					return "\"" + column.Name + "=\" + " + GetMemberVariableName(column) + ".ToString()";
					
				case "bool":
					return "\"" + column.Name + "=\" + (" + GetMemberVariableName(column) + "==true ? 1 : 0 ).ToString()";

				case "string":
				case "Guid":
				case "DateTime":
				case "byte[]":
					return "\"" + column.Name + "='\" + " + GetMemberVariableName(column) + ".ToString()" + " + \"'\"";
				
				case "object":
				default:
					return "\"" + column.Name + "='\" + " + GetMemberVariableName(column) + ".ToString()" + " + \"'\"";
			}
		}
		

    }
}
